import { App, inject, reactive, InjectionKey } from 'vue'

// 定义 Store 的类型注入符号
const storeKey: InjectionKey<Store<any, any, any, any>> = Symbol('store')


// 遍历对象的工具函数
function forEachValue(obj: Record<string, any>, fn: (value: any, key: string) => void) {
    Object.keys(obj).forEach((key) => fn(obj[key], key))
}

// StoreOptions 类型声明，用于泛型
interface StoreOptions<State, Mutations, Actions, Getters> {
    state: State
    mutations?: Mutations
    actions?: Actions
    getters?: Getter s
}

// 通用 Store 类，支持灵活的泛型定义
class Store<
    State = Record<string, any>,
    Mutations = Record<string, (state: State, payload?: any) => void>,
    Actions = Record<string, (context: Store<State, Mutations, Actions, Getters>, payload?: any) => any>,
    Getters = Record<string, (state: State) => any>
> {
    public state: State
    public mutations: Mutations
    public actions: Actions
    public getters: Getters
    private _state: { data: State }
    private _mutations: Record<string, Function>
    private _actions: Record<string, Function>
    private _getters: Record<string, () => any> = {}

    constructor(options: StoreOptions<State, Mutations, Actions, Getters>) {
        // 使用 reactive 创建响应式的 state
        this._state = reactive({ data: options.state })
        this.state = this._state.data

        this.mutations = options.mutations || {} as Mutations
        this.actions = options.actions || {} as Actions
        this.getters = options.getters || {} as Getters

        this._mutations = Object.create(null)
        this._actions = Object.create(null)

        // 注册 mutations
        forEachValue(this.mutations, (mutation, key) => {
            this._mutations[key] = (payload: any) => mutation(this.state, payload)
        })

        // 注册 actions
        forEachValue(this.actions, (action, key) => {
            this._actions[key] = (payload: any) => action(this, payload)
        })

        // 注册 getters
        forEachValue(this.getters, (getter, key) => {
            this._getters[key] = () => getter(this.state)
        })
    }

    // 提供 getter 的访问方式
    get computedGetters() {
        const getters: Record<string, any> = {}
        forEachValue(this._getters, (getter, key) => {
            Object.defineProperty(getters, key, {
                get: getter,
                enumerable: true,
            })
        })
        return getters
    }

    // 安装函数，将 store 注入到 Vue 应用中
    install(app: App, injectKey?: InjectionKey<Store<State, Mutations, Actions, Getters>>) {
        app.provide(injectKey || storeKey, this)
        app.config.globalProperties.$store = this
    }

    // 提供调用 mutation 的方法
    commit(type: keyof Mutations, payload?: any) {
        const mutation = this._mutations[type as string]
        if (!mutation) {
            console.error(`[vuex] unknown mutation type: ${String(type)}`)
            return
        }
        mutation(payload)
    }

    // 提供调用 action 的方法
    dispatch(type: keyof Actions, payload?: any) {
        const action = this._actions[type as string]
        if (!action) {
            console.error(`[vuex] unknown action type: ${String(type)}`)
            return
        }
        return action(payload)
    }
}

// 创建 Store 实例的工厂函数
export function createStore<State, Mutations, Actions, Getters>(
    options: StoreOptions<State, Mutations, Actions, Getters>
): Store<State, Mutations, Actions, Getters> {
    return new Store(options)
}

// 使用 Store 的辅助函数
export function useStore<State, Mutations, Actions, Getters>(
    injectKey: InjectionKey<Store<State, Mutations, Actions, Getters>> = storeKey
): Store<State, Mutations, Actions, Getters> {
    const store = inject(injectKey)
    if (!store) {
        throw new Error('[vuex] store is not provided. Make sure to call `app.use(store)` before using `useStore`.')
    }
    return store
}
